package cn.autumnorange.app.common.consumer.rpc.interceptor.filter;

import cn.autumnorange.app.common.consumer.rpc.ConsumerRPCService;
import cn.autumnorange.app.common.consumer.rpc.header.wrapper.HttpServletRequestRPCWrapper;
import cn.autumnorange.app.common.rpc.RPCIDHeaderStrategy;
import cn.autumnorange.app.common.rpc.RPCWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.filter.RequestContextFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

/**
 * @author wsf
 *     <p>应该最先执行 ServletRequest改为自定义的HttpServletRequestRPCWrapper 在springSecurityOauth2 的配置下
 *     断点测试得RequestContextFilter是没有启用的所以一开始就是默认的
 *     <p>FrameWorkServlet 是在整个springSecurityOauth2 filter过滤链走完再执行其中会将设置RequestContextHolder
 *     HttpServletRequest 自定义个RequestContextFilter 进过滤链就行了 自定义
 *     ServletRequestAttributes(httpServletRequestRPCWrapper, response); 再将ServletRequestAttributes
 *     丢到RequestContextHolder
 * @see HttpServletRequestRPCWrapper 以便重新设置header头信息
 */
@Component
@Order(0)
@Slf4j
public class HttpServletRequestRPCWrapperRequestContextFilter extends RequestContextFilter
    implements RPCIDHeaderStrategy {
  int i = 0;
  private boolean threadContextInheritable = false;

  @Autowired private ConsumerRPCService consumerRPCServiceImpl;

  public HttpServletRequestRPCWrapperRequestContextFilter() {}

  public void setThreadContextInheritable(boolean threadContextInheritable) {
    this.threadContextInheritable = threadContextInheritable;
  }

  protected boolean shouldNotFilterAsyncDispatch() {
    return false;
  }

  protected boolean shouldNotFilterErrorDispatch() {
    return false;
  }

  protected void doFilterInternal(
      HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
      throws ServletException, IOException {

    HttpServletRequestRPCWrapper httpServletRequestRPCWrapper =
        new HttpServletRequestRPCWrapper(request);

    ServletRequestAttributes attributes =
        new ServletRequestAttributes(httpServletRequestRPCWrapper, response);

    this.initContextHolders(httpServletRequestRPCWrapper, attributes);

    //  setRPCIDToHeader(getRPCIDByHeader());
    consumerRPCServiceImpl.setConsumerReadTimeoutToHeader(getRPCIDByHeader());
    consumerRPCServiceImpl.setRPCLockTimeToHeader(getRPCIDByHeader());
    log.info(
        "authorization url:"
            + attributes.getRequest().getRequestURL()
            + " rpcId:"
            + getRPCIDByHeader());
    log.info("消费者执行: " + (++i));
    System.out.println("getId " + request.getSession().getId());
    System.out.println(
        "SPRING_SECURITY_SAVED_REQUEST "
            + request.getSession(false).getAttribute("SPRING_SECURITY_SAVED_REQUEST"));

    Enumeration<String> enumeration = request.getHeaderNames();
    while (enumeration.hasMoreElements()) {
      String name = enumeration.nextElement();
      log.info("headerName:" + name + " : " + request.getHeader(name));
    }
    enumeration = request.getSession(false).getAttributeNames();

    while (enumeration.hasMoreElements()) {
      String name = enumeration.nextElement();
      log.info("sessionAttributeName:" + name + " : " + request.getSession().getAttribute(name));
    }
    try {
      filterChain.doFilter(httpServletRequestRPCWrapper, response);
    } finally {
      this.resetContextHolders();
      if (this.logger.isDebugEnabled()) {
        this.logger.debug("Cleared thread-bound request context: " + request);
      }

      attributes.requestCompleted();
    }
  }

  private void initContextHolders(
      HttpServletRequest request, ServletRequestAttributes requestAttributes) {
    LocaleContextHolder.setLocale(request.getLocale(), this.threadContextInheritable);
    RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
    if (this.logger.isDebugEnabled()) {
      this.logger.debug("Bound request context to thread: " + request);
    }
  }

  private void resetContextHolders() {
    LocaleContextHolder.resetLocaleContext();
    RequestContextHolder.resetRequestAttributes();
  }

  /**
   * consumer端不应该设计可以setRpcId 因为在gateway可能重试到其他consumer,导致rpcId再生成不一致幂等失效 setRpcId应该放到gateway唯一生成
   * 目前没有思路 放到前端先调用服务端生成全局id,再setHeader rpcId请求则简单但不安全
   *
   * @param rpcId
   */
  //  @Override
  //  public void setRPCIDToHeader(String rpcId) {
  //    //    if (rpcId == null) {
  //    //      rpcId = UUID.randomUUID().toString();
  //    //      RPCWrapper.getHttpServletRequestRPCWrapper().setHeader(RPCIDHeaderStrategy.RPCID,
  //    // rpcId);
  //    //      log.info("header rpcId is null conumsumer create rpcId");
  //    //    }
  //    //    log.info("rpcId:" + rpcId);
  //  }

  @Override
  public String getRPCIDByHeader() {
    return RPCWrapper.getHttpServletRequestRPCWrapper().getHeader(RPCIDHeaderStrategy.RPCID);
  }
}
